package com.fingard.dsp.core.biz.impl;

import com.fingard.FGBiz;
import com.fingard.dsp.core.DSPSecurityData;
import com.fingard.dsp.core.biz.DSPService;
import com.fingard.dsp.entity.enums.ENDSPResult;
import com.fingard.dsp.entity.po.EncodeSaltValuePO;
import com.fingard.dsp.tcpserver.RequestNIO;
import com.fingard.dsp.tcpserver.SocketReceiver;
import com.fingard.dsp.tcpserver.ThreadNIO;
import com.fingard.text.StringHelper;
import com.fingard.util.AESUtil;
import com.fingard.util.DateHelper;
import com.fingard.xml.XmlTextReader;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @author Parker on 2020-08-03.
 * @version 1.0
 */

@Service
@Primary
public class DSPServiceImpl implements DSPService {

    private volatile int tmpSeqID = 0;

    @Override
    public String dealTrans(String xmlData, HttpServletRequest request) {
        XmlTextReader retReader = null;
        if (!StringHelper.isNullOrEmpty(xmlData)) {
            if (xmlData.indexOf('<') >= 0) {
                retReader = new XmlTextReader(xmlData);
            } else {
                return getErrorRetStr(ENDSPResult.XMLDATA_FORMAT_ERROR);
            }
        } else {
            return getErrorRetStr(ENDSPResult.XMLDATA_FORMAT_ERROR);
        }

        //验证报文时间和IP地址
        ENDSPResult verifyResult = verifyIPAndDate(retReader, request);
        if (!ENDSPResult.SUCCESS.code().equals(verifyResult.code())) {
            return getErrorRetStr(verifyResult);
        }
        //获取解密之后报文
        String mainData = decodeData(retReader);

        //等待队列处理完成, 再获取返回结果
        CyclicBarrier barrier = new CyclicBarrier(2);
        RequestNIO reqNIO = new RequestNIO(mainData, request, barrier);
        reqNIO.recCompleteTime = reqNIO.connTime = new Date();
        tmpSeqID++;
        reqNIO.seqIDInner = tmpSeqID;
        if (tmpSeqID == Integer.MAX_VALUE) {
            tmpSeqID = 0;
        }
        SocketReceiver socketReceiver = new SocketReceiver(request.getCharacterEncoding());
        socketReceiver.isHttp = true;
        socketReceiver.hostRawString = request.getRequestURL().toString();
        reqNIO.reqSocketReceiver = socketReceiver;
        try {
            ThreadNIO.getInstance().addReq(reqNIO);
            barrier.await();//也阻塞,并且当阻塞数量达到指定数目时同时释放
        } catch (InterruptedException ex) {
            FGBiz.limitMsg.exception("DSPService.dealTrans", ex);
        } catch (BrokenBarrierException ex) {
            FGBiz.limitMsg.exception("DSPService.dealTrans", ex);
        } catch (Exception ex) {
            FGBiz.limitMsg.exception("DSPService.dealTrans", ex);
        }
        return reqNIO.respData;
    }

    /**
     *  验证请求IP是否在IP白名单中及时间是否合法
     * @param retReader 请求报文封装的XML对象
     * @param request HttpServletRequest 获取请求信息
     * @return
     */
    public ENDSPResult verifyIPAndDate(XmlTextReader retReader, HttpServletRequest request) {
        //验证请求IP地址
        ENDSPResult checkResult = ENDSPResult.SUCCESS;

        String reqTime = "";
        String tenantid = "";
        try {
            tenantid = retReader.getFirstTextNotNull("/FINGARD/PUB/TransTenant");
            reqTime = retReader.getFirstTextNotNull("/FINGARD/PUB/TransTimeStamp");
        } catch (Exception ex) {
            FGBiz.limitMsg.exception("DSPService.verifyIPAndDate", ex);
        }
        List<String> queryIPs = DSPSecurityData.getInstance().getIpWhiteList().get(tenantid);
        String reqIp = request.getRemoteAddr();
        if (queryIPs == null || !queryIPs.contains(reqIp)) {
            return ENDSPResult.IP_NOT_VERIFY;
        }

        //检测支付时间
        if (DateHelper.getDifferSecs(new Date(), new Date(Long.parseLong(reqTime))) > 60) {
            return ENDSPResult.REQDATE_NOT_VERIFY;
        }
        return checkResult;
    }

    public String decodeData(XmlTextReader retReader) {
        //待解密
        String mainData = "";

        String xmlData = retReader.getOriXmlString();
        try {
            String tenantid = retReader.getFirstTextNotNull("/FINGARD/PUB/TransTenant");
            mainData = retReader.getFirstTextNotNull("/FINGARD/DIRECTREQ");
            if (StringHelper.isBlankStr(mainData) && xmlData.contains("<DIRECTREQ>")) {
                mainData = xmlData.substring(xmlData.indexOf("<DIRECTREQ>") + "<DIRECTREQ>".length(), xmlData.indexOf("</DIRECTREQ>"));

                List<EncodeSaltValuePO> encodeSaltValuePOS = DSPSecurityData.getInstance().getEncodeSaltValues().get(tenantid);
                String encodeValue = "";
                Date currDate = new Date();
                //根据当前时间过去生效的盐值
                for (EncodeSaltValuePO esp : encodeSaltValuePOS) {
                    if(currDate.compareTo(esp.getValiddate()) >= 0 && currDate.compareTo(esp.getInvaliddate()) < 0){
                        encodeValue = esp.getSaltvalue();
                        break;
                    }
                }
                //根据盐值进行解密操作
//            mainData = AESUtil.encrypt(mainData,encodeValue);
                mainData = AESUtil.decrypt(mainData,encodeValue);
            } else {
                mainData = xmlData;
            }
        } catch (Exception ex) {
            FGBiz.limitMsg.exception("DSPService.decodeData", ex);
        }
        return mainData;
    }

    public String getErrorRetStr(ENDSPResult errorInfo) {
        return "<ATSYH><TransResp><TransParam><RespCode>" + errorInfo.code() + "</RespCode><RespInfo>" + errorInfo.msg() + "</RespInfo></TransParam></TransResp></ATSYH>";
    }
}
